package com.dc.docs._888_面试.concurrent._2_cas;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * Description: Cas ABA 问题复现与解决
 * @author: gdc
 * @date: 2021/6/15
 * @version 1.0
 */
public class Cas_2_Aba {

    private static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);

    private static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);


    public static void main(String[] args) throws InterruptedException {
        System.out.println("========ABA问题的产生=========");
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "线程是否更新成功：" + atomicReference.compareAndSet(100, 101));
            System.out.println(Thread.currentThread().getName() + "线程是否更新成功：" + atomicReference.compareAndSet(101, 100));
        }, "t1").start();

        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + "线程是否更新成功：" + atomicReference.compareAndSet(100, 300) + "，当前值为：" + atomicReference.get());
        }, "t2").start();

        TimeUnit.SECONDS.sleep(3);

        System.out.println("========ABA问题的解决=========");

        new Thread(() -> {
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "线程, 第一次的版本号：" + stamp);

            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            boolean result1 = atomicStampedReference.compareAndSet(100, 101, stamp, stamp + 1);
            System.out.println(Thread.currentThread().getName() + "线程, 是否更新成功：" + result1 + ", 第二次的版本号：" + atomicStampedReference.getStamp());
            boolean result2 = atomicStampedReference.compareAndSet(101,
                    100,
                    atomicStampedReference.getStamp(),
                    atomicStampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + "线程, 是否更新成功：" + result2 + ", 第三次的版本号：" + atomicStampedReference.getStamp());
        }, "t3").start();

        new Thread(() -> {
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "线程, 第一次的版本号：" + stamp);

            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            boolean result = atomicStampedReference.compareAndSet(100, 2008, stamp, stamp + 1);
            System.out.println(Thread.currentThread().getName() + "线程，是否修改成功：" + result
                    + ", 当前的最新值为：" + atomicStampedReference.getReference()
                    + ", 当前的版本号：" + atomicStampedReference.getStamp());
        }, "t4").start();
    }
}
